
/**
 * 功能描述:所有要发送的消息都是以Task方式存在,处理任务超时逻辑
 * ps:登录socket(进入房间)或(登出房间)失败时,直接断开IM连接,不再重连
 * 当前类方法都在主线程中调用
 * 修改时间:
 * 修改描述:
 */
    
public class TaskHandler  {
    private let TAG = String(describing:TaskHandler.self)

  //  private final var TAG = "TaskHandler"//(NSStringFromClass(type(of: TaskHandler)))
    private static var INSTANCE:TaskHandler = TaskHandler();
    
    /**
     * 保存client发送的任务消息,server响应后,从map中移除
     * key: msgId消息唯一标示
     * value: 消息对象封装
     */
    private var taskMap:[String:TaskWrapper] =  [:];

//    private TaskHandler() {
//    }

    public static func getInstance() ->TaskHandler {
        return INSTANCE;
    }

    
    init() {
      //  NotificationCenter.default.addObserver(self, selector: #selector(handleMessage(msg:)), name: NSNotification.Name(rawValue: "sendMessageDelayed"), object: nil)

    }
    
//    @Override
    @objc public func handleMessage(object:[String:Any]) {
        //任务超时回调
        
        IMLog.e(tag: TAG, msg: "sendMsg timeout taskID:\(String(describing: object["taskID"]))  msgId:\(String(describing: object["msgId"]))");
        
        //msg.obj为msgId(uuid)
           if (object["obj"] is String) {
            let task = taskMap[object["obj"] as! String]
            if (task != nil) {
                //停止任务
                stopTask(taskId: task!.taskId);
                if (task!.result != nil) {
                    var map:[String:Any] = [:]
                    map["code"] = ResultCode.TIME_OUT;
                    map["uuid"] = task!.msgId;
                    map["message"] = "响应超时";
                    task!.result!(map);
                    task!.result = nil;
                } else {
                    IMLog.e(tag:TAG, msg:"task timeout callback: task.result is nil");
                }
                checkSetRoomId(cmdId: Int(task!.task!.cmdid), isSuccess: false);
                taskMap.removeValue(forKey: task!.msgId)
            } else {
                IMLog.e(tag:TAG,msg:  "task timeout callback: task is nil");
            }
        }
    }
    /**
     * 任务超时后,直接停止Task重试逻辑
     *
     * @param taskId
     */
    private func stopTask(taskId:Int) {
        
        NetworkService.sharedInstance()?.stopTask(taskId);

    }

    /**
     * 添加任务:发送前调用
     *
     * @param task
     */
    public func addTask( task:TaskWrapper) {
        IMLog.i(tag:TAG,msg:  "addTask taskId: \(task.taskId) msgId:\(task.msgId)  cmdId:\(String(describing: task.task?.cmdid))");
        if (task.isNeedServerResp) {
            //需要获取发送结果时,才开启超时检测

            var msg = [String:Any].init();
            msg["what"] = task.taskId as AnyObject;
            msg["obj"] = task.msgId as AnyObject;
            
            DispatchQueue.main.asyncAfter(deadline: .now()+Double(Const.SEND_MSG_TIMEOUT/1000)) {
                self.handleMessage(object: msg)
    
            }

           // sendMessageDelayed(msg, task.timeOutMs);
        }

        taskMap[task.msgId] = task;
    }

    /**
     * 任务完成时调用(server响应时回调)
     *
     * @param cmdid      server响应码
     * @param isSuccess  是否发送成功
     * @param respBean   server响应的bean
     * @param resultJson server响应的json
     * @return
     */
    public func removeTask(cmdid:Int, isSuccess:Bool,  respBean:RespBean,  resultJson:String) {
        let msgId:String? = respBean != nil ? respBean.msgId : nil;
        IMLog.i(tag: TAG, msg: "removeTask msgId:\(msgId)  cmdId:\(cmdid)  isSucc:\( isSuccess)");
        if(msgId == nil){
                IMLog.e(tag:TAG, msg:"removeTask task.result is nil");
                return;
        }
        if (!msgId!.isEmpty) {
            let task = taskMap[msgId!];
            if task != nil {
               
                //removeMessages(task.taskId);

                if (task!.result != nil) {
                    var map:[String:Any] = [:];
                    map["code"] = isSuccess ? ResultCode.SUCCESS : ResultCode.FAIL;
                    map["uuid"] = msgId;
                    map["respCmdId"] = cmdid;
                    map["message"] = respBean.getMessage();
                    map["resultJson"] = resultJson;
                    task!.result!(map);
                    task!.result = nil;
                } else {
                    IMLog.e(tag:TAG, msg:"removeTask task.result is nil");
                }
                checkSetRoomId(cmdId: Int(task!.task!.cmdid), isSuccess: isSuccess);
                taskMap.removeValue(forKey: msgId!)
            } else {
                IMLog.e(tag:TAG, msg:"removeTask task is nil");
            }
        } else {
            IMLog.e(tag:TAG, msg:"removeTask msgId is nil (server resp  msgId is nil error)");
        }
    }

    /**
     * 断开IM时调用
     */
    public func clear() {
        IMLog.i(tag:TAG, msg:"clear()");
       // removeCallbacksAndMessages(nil);
        for taskWrapper:TaskWrapper in taskMap.values {
            stopTask(taskId: taskWrapper.taskId);
            if (taskWrapper.result != nil) {
                var map:[String:Any] = [:];
                map["code"] = ResultCode.TIME_OUT;
                map["uuid"] = taskWrapper.msgId;
                taskWrapper.result!(map);
                taskWrapper.result = nil;
            }
        }

        taskMap.removeAll();
        IMLog.d(tag:TAG, msg:"clear() finish");
    }

    /**
     * 获取待发送的task
     *
     * @param taskId      任务ID
     * @param userContext 透传字段msgId
     * @return
     */
    public func getTask(taskId:Int, userContext:AnyObject) ->TaskWrapper? {
        var task:TaskWrapper? = nil;
        if (userContext is String) {
            IMLog.i(tag:TAG, msg: "getTask userContext:\(String(describing: userContext.userContext))");
            task = taskMap[userContext as! String];
        } else {
            IMLog.w(tag: TAG, msg: "getTask userContext is nil");
            
            for taskWrapper:TaskWrapper in taskMap.values {
                if (taskWrapper.taskId == taskId) {
                    task = taskWrapper;
                    break;
                }
            }
        }

        if (task != nil && !task!.isNeedServerResp) {
            //client发送的消息不需要获取server响应,发送任务后,直接从队列中删除任务
            IMLog.i(tag:TAG, msg: "getTask task.result is nil,remove task");
            if (task!.result != nil) {
                var map:[String:Any] = [:];
                map["code"] = ResultCode.SUCCESS;
                map["uuid"] = task?.msgId;
                task!.result!(map);
                task!.result = nil;
            }
            taskMap.removeValue(forKey: task!.msgId)
        }
        return task;
    }

    /**
     * 检查设置房间ID
     * 1.进入房间响应后设置roomId
     *
     * @param cmdId     请求消息码
     * @param isSuccess 是否成功
     * @return
     */
    private func checkSetRoomId(cmdId:Int,isSuccess:Bool) {
        if (cmdId == ReqCmdID.CMDID_ENTER_ROOM_REQ) {
            if (!isSuccess) {
                //进入房间失败,清除房间标记
                IMClient.getInstance().setInRoom(inRoom: false);
            }
        }
    }

    /**
     * 判断taskMap中是否包含respBean对象中的msgId
     * <p>
     * 方法在线程中被调用
     *
     * @param respBean
     * @return
     */
    public func isContainMsgId( respBean:RespBean)->Bool {
        if (respBean != nil && !respBean.msgId!.isEmpty && taskMap != nil) {
            return taskMap[respBean.msgId!] != nil;
        }
        return false;
    }

}
